#ifndef GUIDEDNATIVEIMAGEIO_H
#define GUIDEDNATIVEIMAGEIO_H

#include "ImageCoordinateGeometry.h"

#include <QString>
#include <QStringList>
#include <QMap>
#include <QVector>
#include <QDir>
#include <QErrorMessage>

#include "itkGDCMSeriesFileNames.h"
#include "itkSmartPointer.h"
#include "itkImage.h"
#include "itkImageBase.h"
#include "itkImageIOBase.h"

class ImageCoordinateGeometry;

class ImageProperties
{
public:
    ImageProperties() {spacing.fill(0,3);}
    ~ImageProperties() {}

    QString modality;
    QString dataBase;
    QString patientNumber;

    QString series;
    QString uid;
    unsigned long sizeInKBytes;
    QString endian;
    int shift;

    itk::ImageIOBase::IOComponentType pixelType;
    QString pixelTypeString;

    QString lps;
    QVector<unsigned int> dimensions;
    QVector<double> spacing;
    QVector<double> imagePosition;
    QVector<double> imageOrientationVectors[2];

    double rescaleIntercept;
    double rescaleSlope;
    QVector<float> range;
    QString scaleType;

    QMap <QString, QString> labels;
 };

class GuidedNativeImageIO
{

public:
    enum FileFormat {
        FORMAT_DICOM=0, FORMAT_ACT, FORMAT_COUNT};

    enum RawPixelType {
        PIXELTYPE_UCHAR=0, PIXELTYPE_CHAR, PIXELTYPE_USHORT, PIXELTYPE_SHORT,
        PIXELTYPE_UINT, PIXELTYPE_INT, PIXELTYPE_FLOAT, PIXELTYPE_DOUBLE,
        PIXELTYPE_COUNT};

    typedef itk::ImageIOBase ImageIOBase;
    typedef typename ImageIOBase::Pointer ImageIOBasePointer;

    typedef itk::ImageBase<3> ImageBaseType;
    typedef typename ImageBaseType::Pointer ImageBasePointer;

    typedef itk::Image<unsigned int, 3> ACTImageType;
    typedef typename ACTImageType::Pointer ACTImagePointer;

    typedef itk::GDCMSeriesFileNames DICOMNamesGeneratorType;
    typedef DICOMNamesGeneratorType::Pointer DICOMNamesGeneratorPointer;

    FileFormat DetermineFileFormatFromFile(const QStringList &fileNames, const QDir &directory);

    const QStringList& GetDICOMSeriesUID(const QDir &directory);
    QStringList GetACTSeriesUID(const QDir &directory);

    void ReadNativeImage(QString uid);
    void ReadACTROIFile(QString file);

    GuidedNativeImageIO();
    ~GuidedNativeImageIO();

    void DeallocateImage()
    {
        m_ImageIOBase = NULL;
        m_ImageBase = NULL;
    }

    bool IsImageLoaded() const
    { return m_ImageBase.IsNotNull(); }
    
    ImageBaseType* GetImageBase() const
    { return m_ImageBase.GetPointer(); }
    
    ImageProperties* GetImageProperties() const
    { return m_ImageProperties; }

    ImageCoordinateGeometry* GetImageGeometry() const
    { return m_ImageCoordinateGeometry; }

private:
    QDir m_DICOMDirectory;
    std::vector<std::string> m_DICOMFiles;
    DICOMNamesGeneratorPointer m_DICOMNamesGenerator;
    QStringList m_DICOMUids;

    ImageBasePointer m_ImageBase;
    ImageIOBasePointer m_ImageIOBase;
    FileFormat m_FileFormat;
    QStringList m_FileNames;

    ACTImagePointer m_ACTImage;

    ImageCoordinateGeometry *m_ImageCoordinateGeometry;
    ImageProperties *m_ImageProperties;

    void ReadImageProperties();
    template <typename TScalar> void DoReadDICOM();
    template <typename TScalar> void DoReadACT();
    void SortACTFileNames();

    void SplittoQVector(QVector<double> &field, const std::string value);
};

#endif
